home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / dev / misc / fcxref.lha / FCXRef / Src / mref.c < prev    next >
C/C++ Source or Header  |  1999-02-09  |  13KB  |  637 lines

  1. /* :ts=4
  2.  * mref.c
  3.  */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <ctype.h>
  8. #include <unistd.h>
  9.  
  10. #include "dirwalker.h"
  11. #include "stack.h"
  12.  
  13. extern void scanhead(char *file);
  14.  
  15. struct dirstruct {
  16.     struct dirstruct *next;
  17.     char *name;                // név (malloced)
  18.     int par;                // parent (0==root)
  19.     int num;                // sorszám
  20.     int type;                // 0-file, 1-dir, 2-root
  21. };
  22.  
  23. struct dirvect {
  24.     char *name;                // név
  25.     int par;                // szülõ
  26.     int type;                // 0-file, 1-dir, 2-root
  27.     int minus;
  28. };
  29.  
  30. struct fnlist {
  31.     struct fnlist *next;
  32.     struct fnlist *prev;
  33.     char *name;                // függvénynév
  34.     int ln;                    // linenumber    (-1: delted!!)
  35.     int fn;                    // filenumber
  36. };
  37.  
  38. struct optin {
  39.     int dif;                // különbség
  40.     struct fnlist *f;        // elem
  41. };
  42.  
  43. #define MAGIC        0xFA57C8EF
  44.  
  45. #define ED_CED        1
  46. #define ED_GED        0
  47. int opt_edit;
  48. int opt_quiet;
  49. int opt_unique;
  50. int opt_struct;
  51.  
  52. #define ADOC_TERM    12
  53. #define LINEBUFFLEN    300
  54. #define TAB            9
  55. #define MAXFILENAME    300
  56. #define TMPFILE        "T:cqref.TMP"
  57.  
  58. #define ST_NULL        0
  59. #define ST_FILE        1
  60. #define ST_DIR        2
  61. #define ST_ROOT        3
  62.  
  63. struct dirvect *dvec;
  64. int maxnum;
  65. struct dirstruct *first;
  66. struct stack *stk;
  67. struct fnlist *mainfnlist;
  68. int parent;
  69. int number;
  70. int funcnumber,totalfuncnumber;
  71. int chunksize,playsize;
  72. int filenumber;
  73. char *databasename;
  74. static char line[LINEBUFFLEN+1];
  75. FILE *TmpFile;
  76. FILE *OutFile;
  77.  
  78. /*
  79.  * egy teljes path+file-névbõl elkészíti a filenevet
  80.  */
  81. void getpurename(char *fullname,char *name) {
  82.     int i;
  83.  
  84.     if(fullname==NULL) return;
  85.     i=strlen(fullname);
  86.     for(;i>=0&&fullname[i]!=':'&&fullname[i]!='/';i--);
  87.     strcpy(name,&fullname[i+1]);
  88. } // getpurename()
  89.  
  90.  
  91.  
  92. /* behelyezi a listába rendezetten a megadott
  93.  * függvényt
  94.  * ha duplikált, akkor
  95.  * törli az eredeti elemet is.
  96.  * üreslistát nem kezel
  97.  * RET: 1-ok, -1-törölt elem! 0-nem helyezte be
  98.  */
  99. int insertfnlist(struct fnlist *f) {
  100.     struct fnlist *f2,*fo;
  101.     int ret=1;
  102.  
  103.     f2=mainfnlist;
  104.     fo=NULL;
  105.     while(f2!=NULL&&strcmp(f2->name,f->name)<0) {
  106.         fo=f2;
  107.         f2=f2->next;
  108.     }
  109.     if(strcmp(f2->name,f->name)==0) {
  110.         if(opt_quiet==0) fprintf(stderr,"***Warning: identical keys detected (%s)\n",f->name);
  111.         free(f->name);
  112.         free(f);
  113.         ret=0;
  114.         if(opt_unique!=0) {
  115.             if(f2->ln>=0) {
  116.                 f2->ln=-1;            // DELETED
  117.                 ret=-1;
  118.             }
  119.         }
  120.     } else if(fo==NULL) {
  121.         // insert start
  122.         mainfnlist->prev=f;
  123.         f->next=mainfnlist;
  124.         f->prev=NULL;
  125.         mainfnlist=f;
  126.     } else if(f2==NULL) {
  127.         // insert tail
  128.         fo->next=f;
  129.         f->prev=fo;
  130.         f->next=NULL;
  131.     } else {
  132.         // insert before 'f2'
  133.         if(f2->prev!=NULL) f2->prev->next=f;
  134.         f->next=f2;
  135.         f->prev=f2->prev;
  136.         f2->prev=f;
  137.     }
  138.     return(ret);
  139. }
  140.  
  141.  
  142. /* behelyezi a listába rendezetten a megadott
  143.  * függvényt
  144.  * ha duplikált, akkor
  145.  * törli az eredeti elemet is. (opt_unique)
  146.  */
  147. int AddFunc(char *file, char *func,int linenum) {
  148.     struct fnlist *f;
  149.  
  150.     if(NULL==(f=malloc(sizeof(struct fnlist)))) {
  151.         fprintf(stderr,"***Nomem\n");
  152.         return(-1);
  153.     }
  154.     if(NULL==(f->name=malloc(strlen(func)+1))) {
  155.         fprintf(stderr,"***Nomem\n");
  156.         return(-1);
  157.     }
  158.     strcpy(f->name,func);
  159.     f->ln=linenum;
  160.     f->fn=filenumber;
  161.     if(mainfnlist!=NULL) {
  162.         funcnumber+=insertfnlist(f);
  163.     } else {
  164.         funcnumber++;
  165.         mainfnlist=f;
  166.         f->next=NULL;
  167.         f->prev=NULL;
  168.     }
  169.     return(0);
  170. }
  171.  
  172. void freefnlist(struct fnlist *fnl) {
  173.     struct fnlist *f2;
  174.     while(fnl!=NULL) {
  175.         f2=fnl->next;
  176.         if(fnl->name!=NULL) free(fnl->name);
  177.         free(fnl);
  178.         fnl=f2;
  179.     }
  180. }
  181.  
  182. void outword(int a,FILE *o) {
  183.     unsigned char lo,hi;
  184.     lo=(unsigned char)(a&0xff);
  185.     hi=(unsigned char)(a>>8);
  186.     fputc(hi,o);
  187.     fputc(lo,o);
  188. }
  189.  
  190. /*
  191.  * kiírja az out-ot, de, ha az elsõ valahány karaktere megegyezik
  192.  * before-éval, akkor azok helyett csak 1 byte-ot ír ki,
  193.  * értéke: az azonos char-ok száma
  194.  * (egy azonos nem elég)
  195.  * RET: az azonos karakterek az elején (0-0,1 2-2 stb)
  196.  */
  197. int outstr(char *out,char *before) {
  198.     int i;
  199.     if(before==NULL) {
  200.         fprintf(TmpFile,"%s",out);
  201.         return(0);
  202.     }
  203.     for(i=0;out[i]==before[i];i++);
  204.     if(i>=2) {
  205.         fputc(i,TmpFile);
  206.         fprintf(TmpFile,"%s",&out[i]);
  207.     } else {
  208.         fprintf(TmpFile,"%s",out);
  209.     }
  210.     return(i);
  211. }
  212.  
  213. /*
  214.  * OutFile-ba kiír egy index bejegyzést:
  215.  * a 'name' stringet, addig, hogy legalább egy charjában különbözzék
  216.  * 'before'-tõl, formátum:
  217.  * name        \0        pos
  218.  * chars..    byte    3byte
  219.  */
  220. void outindexitem(char *name,char *before,long pos) {
  221.     int i;
  222.     unsigned char c,f1,f2,f3;
  223.  
  224.     if(pos>0xffffff) fprintf(stderr,"***Filepos overflow\n");
  225.     for(i=0;name[i]==before[i];i++) {
  226.         fputc(name[i],OutFile);
  227.     }
  228.     fputc(name[i],OutFile);
  229.     fputc(0,OutFile);
  230.     f1=c=(pos>>16)&0xff;
  231.     fputc(c,OutFile);
  232.     f2=c=(pos>>8)&0xff;
  233.     fputc(c,OutFile);
  234.     f3=c=pos&0xff;
  235.     fputc(c,OutFile);
  236. }
  237.  
  238. /*
  239.  * index és tmpfile készítés
  240.  */
  241. void output(struct fnlist *fnl) {
  242.     char *before=NULL;
  243.     char *beforeold=NULL;
  244.     int counter=0,j,i;
  245.     int mini,minv;
  246.     struct optin *op;
  247.  
  248.     op=calloc(sizeof(struct optin),playsize+1);
  249.     if(op==NULL) {
  250.         fprintf(stderr,"***Nomem\n");
  251.         return;
  252.     }
  253.     while(fnl!=NULL) {
  254.         if(fnl->ln>=0) {
  255.             if(++counter<chunksize) {
  256.                 outstr(fnl->name,before);
  257.                 before=fnl->name;
  258.                 fputc(0,TmpFile);
  259.                 outword(fnl->ln,TmpFile);
  260.                 outword(fnl->fn,TmpFile);
  261.             } else if(counter<(chunksize+playsize)) {
  262.                 j=counter-chunksize;
  263.                 if(j==0) beforeold=before;
  264.                 op[j].f=fnl;
  265.                 for(i=0;fnl->name[i]==before[i];i++);
  266.                 op[j].dif=i;
  267.             } else {
  268.                 minv=9999;
  269.                 mini=0;
  270.                 for(i=0;i<playsize;i++) if(op[i].dif<minv) { minv=op[i].dif; mini=i; }
  271.                 before=beforeold;
  272.                 for(i=0;i<playsize;i++) {
  273.                     if(mini==i) {
  274.                         outindexitem(op[i].f->name,before,ftell(TmpFile));
  275.                         outstr(op[i].f->name,NULL);
  276.                     } else {
  277.                         outstr(op[i].f->name,before);
  278.                     }
  279.                     before=op[i].f->name;
  280.                     fputc(0,TmpFile);
  281.                     outword(op[i].f->ln,TmpFile);
  282.                     outword(op[i].f->fn,TmpFile);
  283.                 }
  284.                 counter=mini;
  285.                 outstr(fnl->name,before);
  286.                 before=fnl->name;
  287.                 fputc(0,TmpFile);
  288.                 outword(fnl->ln,TmpFile);
  289.                 outword(fnl->fn,TmpFile);
  290.             }
  291.         }
  292.         fnl=fnl->next;
  293.     }
  294.     fputc(0,OutFile);            // index vége
  295.     free(op);
  296. }
  297.  
  298. int scanheader(char *name) {
  299.     scanhead(name);
  300.     return(0);
  301. }
  302.  
  303. int scanautodoc(char *name) {
  304.     FILE *f;
  305.     int c=0,i,ln;
  306.     char *l,*onlyname;
  307.  
  308.     if(NULL==(onlyname=malloc(strlen(name)+1))) return(-1);
  309.     f=fopen(name,"rb");
  310.     if(f==NULL) return(0);
  311.     getpurename(name,onlyname);
  312.     ln=1;
  313.     while(c!=EOF) {
  314.         while((c=fgetc(f))!=ADOC_TERM&&c!=EOF) if(c=='\n') ln++;
  315.         if(c!=EOF) {
  316.             ln+=opt_edit;
  317.             line[0]='\0';
  318.             if(NULL==(fgets(line,LINEBUFFLEN,f))) break;
  319.             if(line[0]=='\n') {
  320.                 if(NULL==(fgets(line,LINEBUFFLEN,f))) break;
  321.                 ln++;
  322.             }
  323.             if(line[strlen(line)-1]=='\n') line[strlen(line)-1]='\0';
  324.             for(i=0;line[i]!='/'&&line[i]!='\0';i++);
  325.             if(line[i]=='\0') l=line;
  326.             else l=&line[i+1];
  327.             for(i=0;l[i]!='\0'&&l[i]!=' '&&l[i]!=TAB&&l[i]!='/';i++);
  328.             if(isalpha(l[0])) {
  329.                 if(l[i]=='\0'||l[i]=='/') if(!opt_quiet) fprintf(stderr,"***Warning: Too long line in %s at line %d\n",name,ln);
  330.                 l[i]='\0';
  331.                 AddFunc(name,l,ln);
  332.             }
  333.             ln++;
  334.         }
  335.     }
  336.     fclose(f);
  337.     free(onlyname);
  338.     return(0);
  339. }
  340.  
  341. int dfil2(char *name) {
  342.     int ret=-1;
  343.     switch(name[strlen(name)-1]) {
  344.         case 'c' :
  345.             ret=scanautodoc(name);
  346.             break;
  347.         case 'h' :
  348.             ret=scanheader(name);
  349.             break;
  350.         default :
  351.             fprintf(stderr,"***Wrong filetype: %s\n",name);
  352.             break;
  353.     }
  354.     return(ret);
  355. }
  356.  
  357.  
  358. /* functions for filename generation
  359.  */
  360. struct dirstruct *store(char *name,int type) {
  361. static struct dirstruct *last=NULL;
  362.     struct dirstruct *ds;
  363.     int len;
  364.     if(name==NULL||type==ST_NULL) {
  365.         last=NULL;
  366.         return(NULL);
  367.     }
  368.     ds=malloc(sizeof(struct dirstruct));
  369.     if(ds==NULL) return(NULL);
  370.     ds->num=++number;
  371.     ds->par=parent;
  372.     ds->next=NULL;
  373.     ds->type=type;
  374.     if(NULL==(ds->name=malloc(strlen(name)+2))) {
  375.         free(ds);
  376.         return(NULL);
  377.     }
  378.     switch(type) {
  379.         case ST_FILE :                    // FILE
  380.             getpurename(name,ds->name);
  381.             break;
  382.         case ST_DIR :                    // DIR
  383.             getpurename(name,ds->name);
  384.             strcat(ds->name,"/");
  385.             break;
  386.         case ST_ROOT :                    // ROOT
  387.             strcpy(ds->name,name);
  388.             len=strlen(ds->name)-1;
  389.             if(ds->name[len]!=':'&&ds->name[len]!='/') strcat(ds->name,"/");
  390.             break;
  391.     }
  392.     if(last!=NULL) last->next=ds;
  393.     last=ds;
  394.     return(ds);
  395. }
  396.  
  397. int din1(char *name) {
  398.     store(name,ST_DIR);
  399.     parent=number;
  400.     if(0!=push(stk,number)) {
  401.         fprintf(stderr,"***Error on PUSH\n");
  402.         return(-1);
  403.     }
  404.     return(0);
  405. }
  406.  
  407. int dout1(char *name) {
  408.     long l;
  409.     top(stk,&l);
  410.     if(0!=pop(stk,&l)) {
  411.         fprintf(stderr,"***Error on POP\n");
  412.         return(-1);
  413.     }
  414.     top(stk,&l);
  415.     parent=l;
  416.     return(0);
  417. }
  418.  
  419. int dfil1(char *name) {
  420.     store(name,ST_FILE);
  421.     return(0);
  422. }
  423.  
  424. struct dirvect *makevect(struct dirstruct *f) {
  425.     struct dirvect *dv;
  426.     int i;
  427.     if(f==NULL) return(NULL);
  428.     dv=calloc(sizeof(struct dirvect),number+2);
  429.     if(dv==NULL) return(NULL);
  430.     dv[0].name=NULL;
  431.     dv[0].type=ST_NULL;
  432.     for(i=1;f!=NULL;i++) {
  433.         dv[i].name=f->name;
  434.         f->name=NULL;
  435.         dv[i].par=f->par;
  436.         dv[i].type=f->type;
  437.         f=f->next;
  438.     }
  439.     dv[0].par=i;
  440.     return(dv);
  441. }
  442.  
  443. void freelist(struct dirstruct *f) {
  444.     struct dirstruct *f2;
  445.     while(f!=NULL) {
  446.         f2=f->next;
  447.         if(f->name!=NULL) free(f->name);
  448.         free(f);
  449.         f=f2;
  450.     }
  451.     store(NULL,ST_NULL);
  452. }
  453.  
  454. /* 's' elé fûzi 'n'-et
  455.  * 's'-ben kell elég helynek lennie
  456.  */
  457. int strbefore(char *s,char *n, int slen) {
  458.     int ls,ln;
  459.     char *t;
  460.     ls=strlen(s);
  461.     ln=strlen(n);
  462.     if((ls+ln+1)>slen) return(-1);
  463.     if(NULL==(t=malloc(slen))) return(-1);
  464.     strcpy(t,n);
  465.     strcat(t,s);
  466.     strcpy(s,t);
  467.     free(t);
  468.     return(0);
  469. }
  470.  
  471. char *makefullname(struct dirvect *dv,int index) {
  472. static char fn[MAXFILENAME];
  473.     int p;
  474.     // elkészíti a teljes nevet
  475.     strcpy(fn,dv[index].name);
  476.     p=dv[index].par;
  477.     do {
  478.         strbefore(fn,dv[p].name,MAXFILENAME);
  479.         p=dv[p].par;
  480.     } while(p!=0);
  481.     return(fn);
  482. }
  483.  
  484. /*
  485.  * s-t fordított sorrendben kiírja f-re
  486.  */
  487. void reversewrite(FILE *f,char *s) {
  488.     int i;
  489.     for(i=strlen(s)-1;i>=0;i--) {
  490.         fputc(s[i],f);
  491.     }
  492. }
  493.  
  494. /*
  495.  * ez írja ki a dir/files részt
  496.  */
  497. void makefnlist(struct dirvect *dv) {
  498.     int j,num,deleted;
  499.  
  500.     deleted=0;
  501.     totalfuncnumber=0;
  502.     num=dv[0].par;
  503.     for(j=1;j<num;j++) {
  504.         if(dv[j].type==ST_FILE) {
  505.             funcnumber=0;
  506.             filenumber=j-deleted;
  507.             dfil2(makefullname(dv,j));
  508.             if(funcnumber==0) {
  509.                 // No match in file!!
  510.                 free(dv[j].name);
  511.                 dv[j].name=NULL;
  512.                 deleted++;
  513.             }
  514.             totalfuncnumber+=funcnumber;
  515.         }
  516.         if(dv[j].name!=NULL) dv[j].minus=deleted;
  517.     }
  518.     dv[0].minus=0;
  519.     outword(num-deleted,OutFile);                        // num of dirs/files
  520.     for(j=1;j<num;j++) {
  521.         if(dv[j].name!=NULL) {
  522.             outword(dv[j].par-dv[dv[j].par].minus,OutFile);
  523.             reversewrite(OutFile,dv[j].name);
  524.             fputc(0,OutFile);
  525.         }
  526.     }
  527. }
  528.  
  529. void freevect(struct dirvect *dv) {
  530.     int i,j;
  531.     i=dv[0].par;
  532.     for(j=1;j<i;j++) if(dv[j].name!=NULL) free(dv[j].name);
  533.     free(dv);
  534. }
  535.  
  536. /*
  537.  * OutFile mögé fûzi TmpFile-t
  538.  */
  539. void merge(void) {
  540.     int i;    
  541.     fseek(TmpFile,0,SEEK_SET);
  542.     while(EOF!=(i=fgetc(TmpFile))) fputc(i,OutFile);
  543. }
  544.  
  545.  
  546. int main(int argc,char **argv) {
  547.     struct dirstruct *f;
  548.     int i;
  549.  
  550.     opt_edit=ED_CED;
  551.     opt_quiet=0;
  552.     opt_unique=0;
  553.     opt_struct=0;
  554.     if(argc<3) {
  555.         fprintf(stderr,"Autodoc & Include database builder\n");
  556.         fprintf(stderr,"Usage: %s [options] New-Database Dir/ [Dir/,Dir/,...]\n",argv[0]);
  557.         fprintf(stderr," -q\tQuiet\n");
  558.         fprintf(stderr," -g\tGoldED mode (default: CED mode)\n");
  559.         fprintf(stderr," -u\tUnique keys only\n");
  560.         fprintf(stderr," -s\tAdd structure definitions too\n");
  561.         return(0);
  562.     }
  563.     if(NULL!=(stk=newstack())) {
  564.         for(i=1;i<argc&&argv[i][0]=='-';i++) {
  565.             switch(argv[i][1]) {
  566.                 case 'q' :
  567.                     opt_quiet=1;
  568.                     break;
  569.                 case 'g' :
  570.                     opt_edit=ED_GED;
  571.                     break;
  572.                 case 'u' :
  573.                     opt_unique=1;
  574.                     break;
  575.                 case 's' :
  576.                     opt_struct=1;
  577.                     break;
  578.                 default :
  579.                     fprintf(stderr,"***Invalid option '%c'\n",argv[i][1]);
  580.                     return(0);
  581.                     break;
  582.             }
  583.         }
  584.         if(argc==i) {
  585.             fprintf(stderr,"***Missing database name\n");
  586.             return(0);
  587.         }
  588.         databasename=argv[i++];
  589.         if(argc==i) {
  590.             fprintf(stderr,"***Missing source directory\n");
  591.             return(0);
  592.         }
  593.         OutFile=fopen(databasename,"wb");
  594.         if(OutFile==NULL) {
  595.             fprintf(stderr,"***Can't open database\n");
  596.             return(0);
  597.         }
  598.         TmpFile=fopen(TMPFILE,"wb");
  599.         if(TmpFile==NULL) {
  600.             fprintf(stderr,"***Can't open tmp-file\n");
  601.             return(0);
  602.         }
  603.         fputc(0xFA,OutFile);            // Magic
  604.         fputc(0x57,OutFile);
  605.         fputc(0xC8,OutFile);
  606.         fputc(0xEF,OutFile);
  607.         number=0;
  608.         mainfnlist=NULL;
  609.         first=NULL;
  610.         for(;i<argc;i++) {
  611.             chdir(argv[i]);
  612.             parent=0;
  613.             f=store(argv[i],ST_ROOT);
  614.             if(first==NULL) first=f;
  615.             push(stk,number);
  616.             parent=number;
  617.             dirwalker(argv[i],"#?","#?.(doc|h)",din1,dout1,dfil1);
  618.         }
  619.         dvec=makevect(first);
  620.         freelist(first);
  621.         makefnlist(dvec);                // fill 'mainfnlist'
  622.         chunksize=totalfuncnumber/100;
  623.         if(chunksize<2) chunksize=2;
  624.         playsize=chunksize/3;
  625.         if(playsize==0) playsize=1;
  626.         output(mainfnlist);
  627.         merge();
  628.         freefnlist(mainfnlist);
  629.         freevect(dvec);
  630.         freestack(stk);
  631.         fclose(OutFile);
  632.         fclose(TmpFile);
  633.         unlink(TMPFILE);
  634.     }
  635.     return(0);
  636. }
  637.